#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

from common.const import RepositoryDataTypeEnum, CopyDataTypeEnum
from common.common import check_path_legal, get_local_ips
from common.util.check_utils import check_repo_path
from common.parse_parafile import get_env_variable

from generaldb.saphana.comm.saphana_const import SaphanaJsonConstant, SaphanaPath, SaphanaMetadataKey
from generaldb.saphana.comm.saphana_parse_job_param_base import SaphanaParseJobParamsBase
from generaldb.saphana.comm.saphana_file_operate import log


class SaphanaParseRestoreParam(SaphanaParseJobParamsBase):

    def __init__(self, pid, job_id, subjob_id):
        super(SaphanaParseRestoreParam, self).__init__(pid, job_id, subjob_id)
        self._archive_array = [CopyDataTypeEnum.TAP_ARCHIVE.value, CopyDataTypeEnum.S3_ARCHIVE.value]

    @staticmethod
    def get_hostid_by_node(node):
        return node.get(SaphanaJsonConstant.ID, "")

    def get_log_restore_timestamp(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.EXTEND_INFO, {}) \
            .get(SaphanaJsonConstant.RESTORE_TIMESTAMP, "")

    def get_all_repositories(self):
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if not copies:
            log.error(f"Copies param is null. {self.get_log_common()}")
            return []
        timestamp = self.get_log_restore_timestamp()
        if timestamp:
            # 表示为日志恢复，日志恢复至少有2个副本
            if len(copies) < 2:
                log.error(f"Log restore copies num error. {self.get_log_common()}")
                return []
            data_copy = copies[-2]
        else:
            data_copy = copies[-1]

        return data_copy.get(SaphanaJsonConstant.REPOSITORIES, [])

    def get_log_restore_log_path(self):
        # 获取日志恢复的日志仓单独实现
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if len(copies) < 2:
            # 日志恢复最少有2个副本
            log.error(f"Log restore copies num error. {self.get_log_common()}")
            return ""
        log_copy = copies[-1]
        log_repository = log_copy.get(SaphanaJsonConstant.REPOSITORIES, [])
        return self.get_designated_path_ex(RepositoryDataTypeEnum.LOG_REPOSITORY.value, log_repository)

    def get_resotre_db_name(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.TARGET_ENV, {}) \
            .get(SaphanaJsonConstant.NAME, "")

    def get_nodes(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().TARGET_ENV, {}) \
            .get(SaphanaJsonConstant.NODES, [])

    def get_first_copy_extend_info(self):
        # 获取下发的副本链中第一个副本的extendinfo
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return ""
        copy_type = copies[0].get(SaphanaJsonConstant.TYPE, "")
        if copy_type in self._archive_array:
            return copies[0].get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.EXTEND_INFO, "")
        else:
            return copies[0].get(SaphanaJsonConstant.EXTEND_INFO, "")

    def get_copy_id(self, copy):
        """
        获取恢复副本本身的ID
        """
        copy_type = copy.get(SaphanaJsonConstant.TYPE, "")
        if copy_type in self._archive_array:
            # 如果是归档到磁带副本，需要从extendInfo里拿原始备份副本
            return copy.get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.EXTEND_INFO, {}). \
                get(SaphanaJsonConstant.ARCHIVE_COPY_ID, "")
        return copy.get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.ARCHIVE_COPY_ID, "")

    def get_full_data_copy_id(self):
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return ""
        return self.get_copy_id(copies[0])

    def get_last_copy_id(self):
        """
        获取最后一个副本的copyid, 恢复是，需要最后一个副本的catalog
        """
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return ""
        return copies[-1].get(SaphanaJsonConstant.ID, "")

    def get_all_copy_id(self):
        """
        获取下发的所有数据副本的copyid
        data_copy_id_array：返回数据副本的ID 
        log_copy_id_array：返回日志副本的ID
        """
        data_copy_type_array = [
            CopyDataTypeEnum.FULL_COPY.value, CopyDataTypeEnum.DIFF_COPY.value, \
            CopyDataTypeEnum.INCREMENT_COPY.value, CopyDataTypeEnum.S3_ARCHIVE.value, \
            CopyDataTypeEnum.TAP_ARCHIVE.value
        ]
        data_copy_id_array = []
        log_copy_id_array = []
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return [], []
        for copy in copies:
            copy_id = self.get_copy_id(copy)
            if not copy_id:
                log.error(f"Get copy id failed. {self.get_log_common()}")
                return [], []
            copy_type = copy.get(SaphanaJsonConstant.TYPE, "")
            if copy_type in data_copy_type_array:
                data_copy_id_array.append(copy_id)
            if copy_type == CopyDataTypeEnum.LOG_COPY.value:
                log_copy_id_array.append(copy_id)
        return data_copy_id_array, log_copy_id_array

    def get_all_log_path(self):
        """
        获取下发的所有日志仓路径
        log_path_array:返回所有的日志路径
        """
        path_array_result = []
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if len(copies) < 2:
            # 日志恢复最少有2个副本
            log.error(f"Log restore copies num error. {self.get_log_common()}")
            return path_array_result
        log_copy = copies[-1]
        log_repositories = log_copy.get(SaphanaJsonConstant.REPOSITORIES, [])
        for repository in log_repositories:
            if repository.get(SaphanaJsonConstant.REPOSITORY_TYPE, "") != \
                    RepositoryDataTypeEnum.LOG_REPOSITORY.value:
                continue
            path_array = repository.get(SaphanaJsonConstant.PATH, [])
            if not path_array or not path_array[0]:
                continue
            # 返回取到得路径中的第一个符合合法性校验的
            for path in path_array:
                if check_repo_path(path):
                    path_array_result.append(path)
                    break
        return path_array_result

    def get_restore_db_user(self):
        """
        获取待恢复的数据库的用户名
        """
        user_env = f"{SaphanaJsonConstant.JOB}_{SaphanaJsonConstant.TARGET_ENV}_{SaphanaJsonConstant.AUTH}_" \
                   f"{SaphanaJsonConstant.AUTH_KEY}_{self._pid}"
        return get_env_variable(user_env)

    def get_system_db_user(self):
        """
        获取系统数据库用户名：当目标数据库为系统数据库时，直接取protectEnv.auth.authKey; 当目标数据库为租户数据库时，取
        protectEnv.auth.extendInfo.auth.authKey
        """
        extend_auth_key = f"{SaphanaJsonConstant.JOB}_{SaphanaJsonConstant.TARGET_ENV}_{SaphanaJsonConstant.AUTH}_" \
                          f"{SaphanaJsonConstant.EXTEND_INFO}_{SaphanaJsonConstant.AUTH}_" \
                          f"{SaphanaJsonConstant.AUTH_KEY}_{self._pid}"
        system_db_user = get_env_variable(extend_auth_key)
        return system_db_user if system_db_user else self.get_restore_db_user()

    def get_backup_id(self):
        # 只需要取第一个副本的backupid
        extend_info = self.get_first_copy_extend_info()
        return extend_info.get(SaphanaJsonConstant.BACKUP_ID, "")

    def get_info_by_report_restore_result(self):
        job_id = self._json_param.get(SaphanaJsonConstant.TASK_ID, "")
        status = self._json_param.get(SaphanaJsonConstant.STATUS, "")
        return job_id, status

    def get_self_define_param(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.TARGET_OBJECT, {}) \
            .get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.CUSTOM_PARAMS, "")

    def get_local_ip_by_self_nodes(self):
        nodes = self.get_nodes()
        if not nodes:
            log.error(f"Get nodes failed. {self.get_log_common()}")
            return ""
        local_ip_list = get_local_ips()
        if not local_ip_list:
            log.error(f"Get local ip failed. {self.get_log_common()}")
            return ""
        for node in nodes:
            local_ip = node.get(SaphanaJsonConstant.ENDPOINT, "")
            if local_ip in local_ip_list:
                return local_ip
        return ""

    def get_all_data_copy_backup_path(self):
        # 获取所有数据副本中的backup_path
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant().COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return []
        backup_path_array = []

        for copy in copies:
            copy_type = copy.get(SaphanaJsonConstant.TYPE, "")
            if copy_type == CopyDataTypeEnum.LOG_COPY.value:
                continue

            if copy_type in self._archive_array:
                backup_path = copy.get(SaphanaJsonConstant.EXTEND_INFO, {}). \
                    get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.BACKUP_PATH, "")
            else:
                backup_path = copy.get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.BACKUP_PATH, "")
            if not backup_path:
                log.error(f"Get backup path failed. {self.get_log_common()}")
                return []
            backup_path_array.append(backup_path)
        return backup_path_array

    def get_backup_database_name(self):
        # 获取下发的副本链中第一个副本保护的数据库名称
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return ""
        return copies[0].get(SaphanaJsonConstant.PROTECT_OBJECT, {}).get(SaphanaJsonConstant.NAME, "")

    def get_backup_system_id(self):
        # 获取下发的副本链中第一个副本保护的system id
        first_extend_info = self.get_first_copy_extend_info()
        if not first_extend_info:
            return ""
        return first_extend_info.get(SaphanaMetadataKey.SYSTEM_ID, "")

    def get_backup_multi_tenant_system(self):
        # 获取下发的副本链中第一个副本保护的数据库是否为多租户系统
        first_extend_info = self.get_first_copy_extend_info()
        if not first_extend_info:
            raise Exception("Fail to get backup multi attr.")
        attr = first_extend_info.get(SaphanaJsonConstant.MULTI_TENANT_SYSTEM, "error")
        if attr == "error":
            raise Exception("Fail to get backup multi attr.")
        return attr

    def get_backup_master_hostname(self):
        # 获取下发的副本链中第一个副本执行备份的主节点hostname
        first_extend_info = self.get_first_copy_extend_info()
        if not first_extend_info:
            raise Exception("Fail to get backup multi attr.")
        return first_extend_info.get(SaphanaMetadataKey.MASTER_SYSTEMDB_HOSTNAME, "")

    def get_restore_target_location(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).\
            get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.TARGET_LOCATION, "")

    def get_deploy_type(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.TARGET_OBJECT, {})\
                .get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.DEPLOY_TYPE, "")

    def get_backup_object_uuid(self):
        copies = self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.COPIES, [])
        if not copies:
            log.error(f"Copies is null. {self.get_log_common()}")
            return ""
        return copies[0].get(SaphanaJsonConstant.PROTECT_OBJECT, "").\
            get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.CLUSTER_UUID, "")

    def get_restore_object_uuid(self):
        return self._json_param.get(SaphanaJsonConstant.JOB, {}).get(SaphanaJsonConstant.TARGET_OBJECT, []).\
            get(SaphanaJsonConstant.EXTEND_INFO, {}).get(SaphanaJsonConstant.CLUSTER_UUID, "")
